/*
 * 人人信用管理有限公司版权所有.
 * 
 * @Description:
 * 
 * @author: liyuliang
 * 
 * @date: 20 Apr 2017 10:44:16 am
 * 
 * 注意：本内容仅限于人人信用管理有限公司内部传阅，禁止外泄以及用于其他的商业目的.
 */

package com.rrx360.common.web.tag.ref;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.jsp.JspException;

import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.DigestUtils;

import com.rrx360.common.config.global.GlobalConfig;
import com.rrx360.common.web.util.ResourceFunctions;

public class RefTag extends BaseTag {

  private static final long serialVersionUID = -7956943852019602955L;

  public static final Logger logger = LogManager.getLogger(RefTag.class);

  public static final String CSS_TYPE = "css";

  public static final String JS_TYPE = "js";

  public static final String IMG_TYPE = "img";

  public static final String CSS_TMP = "<link rel=\"stylesheet\" href=\"";

  public static final String LESS_TMP = "<link rel=\"stylesheet/less\" href=\"";

  public static final String JS_TMP = "<script src=\"";

  public static final String IMG_TMP = "<img src=\"";

  public static final String TYPE = "type";

  public static final String URL = "url";

  public static final String ROOT = "root";

  public static final String NAME = "name";

  private static final Set<String> confSet = new HashSet<String>();

  private static final Map<String, String> tmpMap = new HashMap<String, String>();

  private static final Map<String, String> rootMap = new HashMap<String, String>();

  private static final Map<String, String> md5Map = new ConcurrentHashMap<>();

  private static final Map<String, Long> timestampMap = new ConcurrentHashMap<>();

  public static final boolean local = "local".equals(GlobalConfig.get("env"));

  static {
    confSet.add(TYPE);
    confSet.add(URL);
    confSet.add(ROOT);
    confSet.add(NAME);
    tmpMap.put(CSS_TYPE, CSS_TMP);
    tmpMap.put(JS_TYPE, JS_TMP);
    tmpMap.put(IMG_TYPE, IMG_TMP);
  }

  /**
   * 类型
   */
  protected String configType;

  protected String configRoot;

  public int doStartTag() throws JspException {
    String type = configType;
    if (type == null) {
      type = getAttribute(TYPE);
    }
    if (type == null) {
      type = JS_TYPE;
    }

    String name = getAttribute(NAME);
    String content;
    if (name == null) {
      content = processWithUrl(type);
    } else {
      content = processWithName(type, name);
    }
    try {
      this.pageContext.getOut().write(content);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    return SKIP_BODY;
  }

  private String processWithName(String type, String name) {
    String[] paths = ResourceFunctions.getPathByName(name);
    StringBuffer content = new StringBuffer();
    for (String path : paths) {
      if (!path.startsWith("/")) {
        path = "/" + path;
      }
      content.append(getOneContent(type, ResourceFunctions.getStaticRoot() + path));
    }
    return content.toString();
  }

  private String processWithUrl(String type) {
    if (rootMap.size() == 0) {
      rootMap.put(JS_TYPE, ResourceFunctions.getJsRoot());
      rootMap.put(CSS_TYPE, ResourceFunctions.getCssRoot());
      rootMap.put(IMG_TYPE, ResourceFunctions.getImgRoot());
    }

    /** 获取root */
    String root = configRoot;
    if (root == null) {
      root = getAttribute(ROOT);
      if (root == null) {
        root = rootMap.get(type);
      }
    }

    String src = getAttribute(URL);
    if (src == null) {
      return "";
    }
    if (!src.startsWith("/")) {
      src = "/" + src;
    }
    String path = root + src;
    String content = getOneContent(type, path);
    return content;
  }

  private String getOneContent(String type, String path) {
    String tmp = null;
    if ((!ResourceFunctions.isLess()) && CSS_TYPE.equals(type) && path.endsWith(".less")) {
      path = path.substring(0, path.length() - 5) + ".css";
    }
    if ((ResourceFunctions.isLess()) && CSS_TYPE.equals(type) && path.endsWith(".less")) {
      tmp = LESS_TMP;
    } else {
      tmp = tmpMap.get(type);
    }
    String realPath = ResourceFunctions.getRealPath(path);
    String v = getVersionByMd5(type, realPath);

    StringBuilder attr = new StringBuilder();
    for (Iterator<String> it = attributeMap.keySet().iterator(); it.hasNext();) {
      String key = it.next();
      if (!confSet.contains(key)) {
        attr.append(" " + key + "=\"" + getAttribute(key) + "\"");
      }
    }
    String content = tmp + path + v + "\"" + attr.toString();
    if (JS_TYPE.equals(type)) {
      content += "></script>";
    } else {
      content += "/>";
    }
    content += "\n";
    return content;
  }

//  private String getVersionByTime(String type, String realPath) {
//    File f = new File(realPath);
//    String v = "";
//    if (f.exists()) {
//      v = "?t=" + f.lastModified();
//      if (JS_TYPE.equals(type)) {
//        v += ".js";
//      } else if (CSS_TYPE.equals(type)) {
//        if (realPath.equals(".less")) {
//          v += ".less";
//        } else {
//          v += ".css";
//        }
//      } else {
//        String fileName = f.getName();
//        int pos = fileName.lastIndexOf('.');
//        if (pos > 0) {
//          v += fileName.substring(pos);
//        }
//      }
//    }
//    return v;
//  }

  private String getVersionByMd5(String type, String realPath) {
    // only for local has concurrent issue
    if (local) {
      File f = new File(realPath);
      Long timestamp = f.lastModified();
      Long oldTimestamp = timestampMap.get(realPath);
      if (!timestamp.equals(oldTimestamp)) {
        md5Map.remove(realPath);
        timestampMap.put(realPath, timestamp);
      }
    }

    String versionInfo = md5Map.get(realPath);
    if (versionInfo != null) {
      return versionInfo;
    }
    File f = new File(realPath);
    String v = "?v=";
    if (f.exists()) {
      try {
        v += DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(f)).substring(0, 8);
      } catch (IOException e) {
        logger.error(e.getMessage(), e);
        v += "ERROR";
      }
    } else {
      v += "NONE";
    }

    if (JS_TYPE.equals(type)) {
      v += ".js";
    } else if (CSS_TYPE.equals(type)) {
      if (realPath.endsWith(".less")) {
        v += ".less";
      } else {
        v += ".css";
      }
    } else {
      String fileName = f.getName();
      int pos = fileName.lastIndexOf('.');
      if (pos > 0) {
        v += fileName.substring(pos);
      }
    }
    md5Map.put(realPath, v);
    return v;
  }

}
